package com.acme.bankapp.services;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.acme.bankapp.domain.BankService;
import com.acme.bankapp.domain.Client;
import com.acme.bankapp.domain.accounting.Account;
import com.acme.bankapp.domain.accounting.CheckingAccount;

public class ReportService {
	
	public static final String ACCOUNTS_INFORMATION_REPORT_HEADER = "Accounts";
	public static final String CLIENTS_LIST_REPORT_HEADER = "Bank clients";
	public static final String CLIENTS_ACCOUNTS_REPORT_HEADER = "Clients accounts";
	
	final BankService bankService;

	public ReportService(BankService bankService){
		this.bankService = bankService;
	}
	
	/**
	 * Get amount of clients
	 * @return
	 */
	public int getNbOfCustomers(){
		return bankService.getBank().getClients().size();
	}
	
	/**
	 * Get amount of accounts
	 * @return
	 */
	public int getNbOfAccounts(){
		int count = 0;
		for(Client client  : bankService.getBank().getClients()){
			count+=client.getAccounts().size();
		}
		return count;
	}
	
	/**
	 * Collection of account, ordered by amount to withdraw
	 * @return
	 */
	public List<Account> getAccountsSortedBySum(){	
		List<Account> accounts = new LinkedList<>();
		for(Client client : bankService.getBank().getClients()){
			accounts.addAll(client.getAccounts());
		}
		
		Collections.sort(accounts, new Comparator<Account>() {
			@Override
			public int compare(Account a1, Account a2) {
				Double a = a1.maximumAmountToWithdraw();
				Double b = a2.maximumAmountToWithdraw();
				return -a.compareTo(b);
			}
		});
		
		return accounts;
	}
	
	/**
	 * Get total credit of banks client.
	 * Only for CheckingAccounts
	 * @return
	 */
	public double getBankCredit(){
		double sum = 0.;
		for(Client client : bankService.getBank().getClients()){
			for(Account account : client.getAccounts()){
				if(account instanceof CheckingAccount){
					sum+=((CheckingAccount) account).getOverdraft();
				}
			}
		}
		return sum;
	}
	
	/**
	 * Get clients with there accounts
	 * @return
	 */
	public Map<String, Collection<Account>> getCustomerAccount(){
		Map<String, Collection<Account>> map = new HashMap<>();
		for(Client client : bankService.getBank().getClients()){
			map.put(client.getName(), client.getAccounts());
		}
		return map;
	}
	
	/**
	 * Bank's clients list report
	 * 
	 * @param bank
	 *            Bank
	 * @return Report
	 */
	public String reportBankClients() {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(CLIENTS_LIST_REPORT_HEADER).append("\n");
		for (Client client : bankService.getBank().getClients()) {
			builder.append(client.getClientSalutation()).append("\n");
		}
		return builder.toString();
	}

	/**
	 * Amounts to withdraw report over all clients
	 * 
	 * @param bank
	 * @return report
	 */
	public String reportAccountsInformation() {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(ACCOUNTS_INFORMATION_REPORT_HEADER)
				.append("\n");
		for (Client client : bankService.getBank().getClients()) {
			builder.append(getAccountsInformation(client));
		}

		return builder.toString();
	}

	/**
	 * Client's account report
	 * 
	 * @param client
	 *            Client
	 * @return report
	 */
	public String reportClientsAccounts(Client client) {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(CLIENTS_ACCOUNTS_REPORT_HEADER)
				.append("\n");
		builder.append(getAccountsInformation(client));

		return builder.toString();
	}

	private String getAccountsInformation(Client client) {
		return client.toString();
	}
	
}
